<template>
  <qs-dialog
    v-model="visible"
    :append-to-body="appendToBody"
    :center="center"
    :close-on-click-modal="closeOnClickModal"
    :close-on-press-escape="closeOnPressEscape"
    :confirm-loading="confirmLoading"
    :custom-class="customClass"
    :destroy-on-close="destroyOnClose"
    :draggable="draggable"
    :fullscreen="fullscreen"
    :loading="loading"
    :loading-text="loadingText"
    :lock-scroll="lockScroll"
    :modal="modal"
    :show-close="showClose"
    :title="title"
    :top="top"
    :width="width"
    @cancel="handleCancel"
    @close="handleClose"
    @closed="handleClosed"
    @confirm="handleConfirm"
    @open="handleOpen"
    @opened="handleOpened"
  >
    <div class="form-container">
      <el-form
        ref="formRef"
        class="dialog-form"
        :disabled="disabled"
        :label-position="labelPosition"
        :label-width="labelWidth"
        :model="form"
        :rules="formRules"
        :size="size"
        :status-icon="statusIcon"
      >
        <el-row :gutter="rowGutter">
          <template v-for="field in visibleFields" :key="field.prop">
            <el-col
              :lg="field.lg || getFieldSpan(field)"
              :md="field.md || getFieldSpan(field)"
              :sm="field.sm || (getFieldSpan(field) >= 12 ? 24 : 12)"
              :span="getFieldSpan(field)"
              :style="{ marginBottom: '18px' }"
              :xl="field.xl || getFieldSpan(field)"
              :xs="field.xs || (getFieldSpan(field) >= 12 ? 24 : 24)"
            >
              <el-form-item
                :class="{ 'is-fullwidth': isFullWidthField(field) }"
                :label="field.label"
                :prop="field.prop"
                :required="field.required || (formRules[field.prop] && formRules[field.prop].some((rule) => rule.required))"
              >
                <!-- 组件内容 -->
                <slot v-if="$slots[`field-${field.prop}`]" :field="field" :form="form" :name="`field-${field.prop}`"></slot>
                <template v-else>
                  <!-- 根据组件类型渲染 -->
                  <template v-if="field.component === 'select'">
                    <el-select
                      v-model="form[field.prop]"
                      :allow-create="field.allowCreate"
                      :clearable="field.clearable !== false"
                      :collapse-tags="field.collapseTags"
                      :default-first-option="field.defaultFirstOption"
                      :disabled="field.disabled"
                      :filterable="field.filterable"
                      :multiple="field.multiple"
                      :placeholder="field.placeholder"
                      style="width: 100%"
                      @visible-change="(visible) => handleVisibleChange(visible, field)"
                    >
                      <el-option v-for="option in field.options || []" :key="option.value" :label="option.label" :value="option.value" />
                    </el-select>
                  </template>
                  <template v-else>
                    <!-- 其他组件类型通过动态组件方式渲染 -->
                    <component :is="getComponentByType(field.component)" v-model="form[field.prop]" v-bind="getComponentProps(field)" />
                  </template>
                </template>
              </el-form-item>
            </el-col>
          </template>
        </el-row>

        <!-- 自定义表单内容 -->
        <slot :form="form" name="form-content"></slot>
      </el-form>
    </div>
  </qs-dialog>
</template>

<script lang="ts" setup>
import {
  ElCascader,
  ElCheckboxGroup,
  ElDatePicker,
  ElInput,
  ElInputNumber,
  ElRadioGroup,
  ElSelect,
  ElSwitch,
  ElTimePicker,
} from 'element-plus'
import { type PropType, computed, defineEmits, defineProps, reactive, watch } from 'vue'
import { useFormDialog } from '../../hooks/useDialog'
import QsDialog from './index.vue'

// 字段类型定义
interface FieldOption {
  label: string
  value: any
}

interface FormField {
  label: string
  prop: string
  component: string
  required?: boolean
  placeholder?: string
  colSpan?: number // 传统的列宽配置
  span?: number // 新的响应式列宽配置
  xs?: number // 超小屏幕列宽
  sm?: number // 小屏幕列宽
  md?: number // 中等屏幕列宽
  lg?: number // 大屏幕列宽
  xl?: number // 超大屏幕列宽
  fullWidth?: boolean // 是否占据整行
  visible?: boolean
  disabled?: boolean
  clearable?: boolean
  multiple?: boolean
  options?: FieldOption[]
  optionsPath?: string
  rules?: any[]
  min?: number
  max?: number
  step?: number
  rows?: number
  props?: Record<string, any>
  type?: string
  valueFormat?: string
  filterable?: boolean
  allowCreate?: boolean
  defaultFirstOption?: boolean
  collapseTags?: boolean
  activeValue?: any
  inactiveValue?: any
  activeText?: string
  inactiveText?: string
  defaultValue?: any
}

// 组件属性定义
const props = defineProps({
  // 显示控制
  modelValue: {
    type: Boolean,
    default: false,
  },

  // 基础属性
  title: {
    type: String,
    default: '',
  },
  width: {
    type: [String, Number],
    default: '50%',
  },
  fullscreen: {
    type: Boolean,
    default: false,
  },
  top: {
    type: String,
    default: '15vh',
  },

  // 行为控制
  modal: {
    type: Boolean,
    default: true,
  },
  appendToBody: {
    type: Boolean,
    default: false,
  },
  lockScroll: {
    type: Boolean,
    default: true,
  },
  customClass: {
    type: String,
    default: '',
  },
  closeOnClickModal: {
    type: Boolean,
    default: true,
  },
  closeOnPressEscape: {
    type: Boolean,
    default: true,
  },
  showClose: {
    type: Boolean,
    default: true,
  },
  beforeClose: {
    type: Function as PropType<(done: () => void) => void>,
    default: undefined,
  },
  destroyOnClose: {
    type: Boolean,
    default: false,
  },
  center: {
    type: Boolean,
    default: false,
  },
  draggable: {
    type: Boolean,
    default: false,
  },

  // 加载状态
  loading: {
    type: Boolean,
    default: false,
  },
  loadingText: {
    type: String,
    default: '加载中...',
  },
  confirmLoading: {
    type: Boolean,
    default: false,
  },

  // 表单相关
  formData: {
    type: Object,
    default: () => ({}),
  },
  fields: {
    type: Array as () => FormField[],
    default: () => [],
  },
  rules: {
    type: Object,
    default: () => ({}),
  },
  labelWidth: {
    type: [String, Number],
    default: '120px',
  },
  labelPosition: {
    type: String as PropType<'top' | 'left' | 'right'>,
    default: 'right',
  },
  disabled: {
    type: Boolean,
    default: false,
  },
  size: {
    type: String as PropType<'' | 'default' | 'small' | 'large'>,
    default: 'default',
  },
  statusIcon: {
    type: Boolean,
    default: false,
  },
  rowGutter: {
    type: Number,
    default: 20,
  },
  defaultColSpan: {
    type: Number,
    default: 24,
  },

  // 表单行为
  validateOnSubmit: {
    type: Boolean,
    default: true,
  },
  resetOnClose: {
    type: Boolean,
    default: false,
  },
})

// 组件事件
const emit = defineEmits(['update:modelValue', 'open', 'opened', 'close', 'closed', 'cancel', 'confirm', 'form-change', 'validation-error'])

/**
 * 配置表单规则 - 合并props.rules和fields中的rules
 * 优先使用字段自己的rules，如果字段标记为required但没有规则，添加默认规则
 */
const formRules = computed(() => {
  // 初始化规则对象，包含传入的rules
  const rules: Record<string, any[]> = { ...props.rules }

  // 遍历所有字段，收集规则
  props.fields.forEach((field: FormField) => {
    // 如果字段有自己的rules，优先使用字段的rules
    if (field.rules && field.rules.length > 0) {
      if (rules[field.prop]) {
        // 合并规则，避免重复
        const existingRules = rules[field.prop]
        field.rules.forEach((rule) => {
          // 判断规则是否已存在
          const ruleExists = existingRules.some((existingRule) => JSON.stringify(existingRule) === JSON.stringify(rule))
          if (!ruleExists) {
            existingRules.push(rule)
          }
        })
      } else {
        rules[field.prop] = [...field.rules]
      }
    }
    // 如果字段标记为required，但没有对应的required规则，添加默认的required规则
    else if (field.required && (!rules[field.prop] || !rules[field.prop].some((rule) => rule.required))) {
      if (!rules[field.prop]) {
        rules[field.prop] = []
      }
      rules[field.prop].push({
        required: true,
        message: `${field.label}是必填项`,
        trigger: field.component === 'select' || field.component === 'radio' ? 'change' : 'blur',
      })
    }
  })

  return rules
})

// 可见字段
const visibleFields = computed(() => {
  return props.fields.filter((field: FormField) => field.visible !== false)
})

// 使用表单对话框Hook
const { visible, form, formRef, formState, validate, resetFields, setForm, open, close } = useFormDialog({
  visible: props.modelValue,
  title: props.title,
  beforeClose: props.beforeClose,
  draggable: props.draggable,
  validateOnSubmit: props.validateOnSubmit,
  resetOnClose: props.resetOnClose,
})

// 获取组件类型
const getComponentByType = (type: string) => {
  const componentMap: Record<string, any> = {
    input: ElInput,
    'input-number': ElInputNumber,
    select: ElSelect,
    switch: ElSwitch,
    radio: ElRadioGroup,
    checkbox: ElCheckboxGroup,
    'date-picker': ElDatePicker,
    'time-picker': ElTimePicker,
    textarea: ElInput,
    cascader: ElCascader,
  }

  return componentMap[type] || 'div'
}

// 获取组件属性
const getComponentProps = (field: FormField) => {
  // 基础属性
  const props: Record<string, any> = {
    placeholder: field.placeholder,
    disabled: field.disabled,
  }

  // 根据组件类型添加特定属性
  switch (field.component) {
    case 'input': {
      props.clearable = field.clearable !== false
      break
    }
    case 'textarea': {
      props.type = 'textarea'
      props.rows = field.rows || 3
      break
    }
    case 'input-number': {
      props.min = field.min
      props.max = field.max
      props.step = field.step || 1
      props.style = 'width: 100%'
      break
    }
    case 'select': {
      props.clearable = field.clearable !== false
      props.multiple = field.multiple
      props.filterable = field.filterable
      props.allowCreate = field.allowCreate
      props.defaultFirstOption = field.defaultFirstOption
      props.collapseTags = field.collapseTags
      props.style = 'width: 100%'
      props['onVisible-change'] = (visible: boolean) => handleVisibleChange(visible, field)
      // 不再直接设置children属性，改为使用template方式
      break
    }
    case 'date-picker': {
      props.type = field.type || 'date'
      props.valueFormat = field.valueFormat || 'YYYY-MM-DD'
      props.style = 'width: 100%'
      break
    }
    case 'time-picker': {
      props.valueFormat = field.valueFormat || 'HH:mm:ss'
      props.style = 'width: 100%'
      break
    }
    case 'switch': {
      props.class = 'switch-control'
      props['active-value'] = field.activeValue === undefined ? true : field.activeValue
      props['inactive-value'] = field.inactiveValue === undefined ? false : field.inactiveValue
      props['active-text'] = field.activeText || ''
      props['inactive-text'] = field.inactiveText || ''
      break
    }
    case 'cascader': {
      props.options = getOptions(field)
      props.props = field.props
      props.clearable = field.clearable !== false
      props.style = 'width: 100%'
      break
    }
  }

  return props
}

// 选项缓存
const optionsCache = reactive<Record<string, any[]>>({})

// 获取选项
const getOptions = (field: FormField) => {
  // 先查找缓存
  if (optionsCache[field.prop]) {
    return optionsCache[field.prop]
  }

  // 直接使用选项
  if (field.options) {
    optionsCache[field.prop] = field.options
    return field.options
  }

  // 返回空数组
  return []
}

// 处理下拉框展开
const handleVisibleChange = async (visible: boolean, field: FormField) => {
  if (visible && field.optionsPath && !optionsCache[field.prop]) {
    try {
      // 这里可以实现远程加载选项
      // const response = await fetchOptions(field.optionsPath)
      // optionsCache[field.prop] = response.data
    } catch (error) {
      console.error('加载选项失败:', error)
    }
  }
}

/**
 * 同步modelValue和visible
 * 确保组件内部状态与外部控制保持一致
 */
watch(
  () => props.modelValue,
  (newVal) => {
    if (newVal !== visible.value) {
      visible.value = newVal
    }
  }
)

watch(
  () => visible.value,
  (newVal) => {
    if (newVal !== props.modelValue) {
      emit('update:modelValue', newVal)
    }
  }
)

/**
 * 监听表单数据变化
 * 仅在以下情况设置表单数据：
 * 1. 弹窗首次打开时
 * 2. 表单未被用户修改过
 * 3. 表单被重置后
 */
watch(
  () => props.formData,
  (newFormData) => {
    // 交由useFormDialog内部逻辑处理数据设置条件
    setForm(newFormData)
  },
  { immediate: true, deep: true }
)

/**
 * 监听表单字段变化，通知父组件
 */
watch(
  () => form.value,
  (newForm) => {
    emit('form-change', JSON.parse(JSON.stringify(newForm)))
  },
  { deep: true }
)

// 事件处理
const handleOpen = () => {
  emit('open')
}

const handleOpened = () => {
  emit('opened')
}

const handleClose = () => {
  emit('close')
}

const handleClosed = () => {
  emit('closed')
}

const handleCancel = () => {
  emit('cancel')
}

/**
 * 处理表单提交确认
 * 1. 执行表单验证
 * 2. 验证通过，发送确认事件并传递表单数据
 * 3. 验证失败，发送验证错误事件
 */
const handleConfirm = () => {
  if (!formRef.value) {
    emit('confirm', JSON.parse(JSON.stringify(form.value)))
    return
  }

  // 执行表单验证
  formRef.value.validate((valid, fields) => {
    if (valid) {
      // 验证通过，发送深拷贝的表单数据
      const formData = JSON.parse(JSON.stringify(form.value))
      emit('confirm', formData)
    } else {
      // 验证失败，发送验证错误事件
      emit('validation-error', fields)
    }
  })
}

// 判断字段是否应该占据整行
const isFullWidthField = (field: FormField) => {
  // 如果明确设置了fullWidth属性，使用它
  if (field.fullWidth !== undefined) {
    return field.fullWidth
  }

  // 根据组件类型自动判断
  if (field.component === 'textarea') {
    return true
  }

  // 特殊字段名称判断
  const fullWidthProps = ['description', 'remark', 'comment', 'content', 'address', 'positionDescription']
  if (fullWidthProps.includes(field.prop)) {
    return true
  }

  return false
}

// 获取字段的列宽
const getFieldSpan = (field: FormField) => {
  // 优先使用span配置
  if (field.span !== undefined) {
    return field.span
  }

  // 其次使用colSpan配置
  if (field.colSpan !== undefined) {
    return field.colSpan
  }

  // 如果是需要占满整行的字段
  if (isFullWidthField(field)) {
    return 24
  }

  // 开关组件布局优化
  if (field.component === 'switch') {
    return 8
  }

  // 单选按钮和复选框使用更合适的宽度
  if (['radio', 'checkbox'].includes(field.component)) {
    return 12
  }

  // 数字输入、日期选择等组件使用中等宽度
  if (['input-number', 'date-picker', 'time-picker', 'select'].includes(field.component)) {
    return 12
  }

  // 根据字段名特征判断
  if (/name|title|label|phone|email|code|date|time/.test(field.prop)) {
    return 12
  }

  // 如果字段名包含"id"或"Id"，通常是较短的输入
  if (/[Ii]d$/.test(field.prop)) {
    return 12
  }

  // 默认为中等宽度
  return 12
}

// 组件方法暴露
defineExpose({
  // 暴露引用
  formRef,

  // 暴露状态
  visible,
  form,
  formState,

  // 暴露方法
  open,
  close,
  validate,
  resetFields,
  setForm,
})
</script>

<style>
/* 使用Element Plus原生样式，删除自定义样式 */
.form-container {
  padding: 5px;
}

.dialog-form {
  padding: 0 10px;
}

/* 添加表单布局优化样式 */
.el-row {
  margin-bottom: 15px;
}

.el-form-item {
  margin-bottom: 18px;
}

.el-form-item.is-fullwidth {
  margin-bottom: 22px;
}

.switch-control {
  width: 100%;
  display: flex;
  align-items: center;
}
</style>
